package com.jn.erp.web.api.sys.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jn.erp.common.constant.CacheConstants;
import com.jn.erp.common.constant.UserConstants;
import com.jn.erp.common.exception.ServiceException;
import com.jn.erp.common.utils.StringUtils;
import com.jn.erp.common.utils.spring.SpringUtils;
import com.jn.erp.security.redis.RedisCache;
import com.jn.erp.web.api.sys.entity.SysOrg;
import com.jn.erp.web.api.sys.mapper.SysOrgMapper;
import com.jn.erp.web.api.sys.service.SysOrgService;
import com.jn.erp.web.result.TreeSelect;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <pre>
 *
 * </pre>
 *
 * @author sunjiyong
 * @since 2024/8/28 15:45
 */
@Service
public class SysOrgServiceImpl extends ServiceImpl<SysOrgMapper, SysOrg> implements SysOrgService {

    /**
     * 项目启动时，初始化机构信息到缓存
     */
    @PostConstruct
    public void init() {
        loadingDeptCache();
    }



    @Override
    public List<TreeSelect> selectOrgTreeList(SysOrg sysOrg) {
        QueryWrapper<SysOrg> qw = new QueryWrapper<>();
        if (StringUtils.isNotBlank(sysOrg.getName())) {
            qw.like("name", "%" + sysOrg.getName() + "%");
        }

        if (sysOrg.getState()!=null) {
            qw.eq("state", sysOrg.getState());
        }

        List<SysOrg> orgs = baseMapper.selectList(qw);

        return buildDeptTreeSelect(orgs);
    }


    /**
     * 校验部门名称是否唯一
     *
     * @param sysOrg 部门信息
     * @return 结果
     */
    @Override
    public boolean checkDeptNameUnique(SysOrg sysOrg) {
        Long deptId = StringUtils.isNull(sysOrg.getId()) ? -1L : sysOrg.getId();
        QueryWrapper<SysOrg> qw = new QueryWrapper<>();
        qw.eq("name",sysOrg.getName());
        qw.eq("pid",sysOrg.getPid());
        qw.eq("deleted",0);
        SysOrg info = baseMapper.selectOne(qw);
        if (StringUtils.isNotNull(info) && info.getId().longValue() != deptId.longValue()) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
    }


    /**
     * 新增保存部门信息
     *
     * @param sysOrg 部门信息
     * @return 结果
     */
    @Override
    public int insertDept(SysOrg sysOrg) {

        SysOrg info = baseMapper.selectById(sysOrg.getPid());
        // 如果父节点不为正常状态,则不允许新增子节点
        if (info.getState()) {
            throw new ServiceException("部门停用，不允许新增");
        }
        sysOrg.setIdPath(info.getIdPath() + "," + sysOrg.getPid());
        return baseMapper.insert(sysOrg);
    }


    /**
     * 重置字典缓存数据
     */
    @Override
    public void resetDeptCache()
    {
        clearDeptCache();
        loadingDeptCache();
    }


    /**
     * 查询部门是否存在用户
     *
     * @param orgId 部门ID
     * @return 结果 true 存在 false 不存在
     */
    @Override
    public boolean checkDeptExistUser(Long orgId) {
        int result = baseMapper.checkDeptExistUser(orgId);
        return result > 0;
    }

    @Override
    public int selectNormalChildrenDeptById(Long orgId) {
        return baseMapper.selectNormalChildrenDeptById(orgId);
    }


    public void clearDeptCache() {
        Collection<String> keys = SpringUtils.getBean(RedisCache.class).keys(CacheConstants.SYS_DEPT_KEY + "*");
        SpringUtils.getBean(RedisCache.class).deleteObject(keys);
    }

    public void loadingDeptCache() {
        SysOrg dept = new SysOrg();
        dept.setState(false);
        QueryWrapper<SysOrg> qw = new QueryWrapper<>();
        qw.eq("state","0");
        List<SysOrg> sysDeptList = baseMapper.selectList(qw);
        Map<Long, SysOrg> sysDepts = sysDeptList.stream().collect(Collectors.toMap(d -> d.getId(), Function.identity()));
        for (Map.Entry<Long, SysOrg> entry : sysDepts.entrySet()) {
            SpringUtils.getBean(RedisCache.class).setCacheObject(CacheConstants.SYS_DEPT_KEY + entry.getKey(), entry.getValue());
        }

    }

    /**
     * 构建前端所需要下拉树结构
     *
     * @param depts 部门列表
     * @return 下拉树结构列表
     */
    @Override
    public List<TreeSelect> buildDeptTreeSelect(List<SysOrg> depts) {
        List<SysOrg> deptTrees = buildDeptTree(depts);
        return deptTrees.stream().map(TreeSelect::new).collect(Collectors.toList());
    }

    /**
     * 构建前端所需要树结构
     *
     * @param depts 部门列表
     * @return 树结构列表
     */
    public List<SysOrg> buildDeptTree(List<SysOrg> depts) {
        List<SysOrg> returnList = new ArrayList<SysOrg>();
        List<Long> tempList = depts.stream().map(SysOrg::getId).collect(Collectors.toList());
        for (SysOrg dept : depts) {
            // 如果是顶级节点, 遍历该父节点的所有子节点
            if (!tempList.contains(dept.getPid())) {
                recursionFn(depts, dept);
                returnList.add(dept);
            }
        }
        if (returnList.isEmpty()) {
            returnList = depts;
        }
        return returnList;
    }

    /**
     * 递归列表
     */
    private void recursionFn(List<SysOrg> list, SysOrg t) {
        // 得到子节点列表
        List<SysOrg> childList = getChildList(list, t);
        t.setChildList(childList);
        for (SysOrg tChild : childList) {
            if (hasChild(list, tChild)) {
                recursionFn(list, tChild);
            }
        }
    }


    /**
     * 得到子节点列表
     */
    private List<SysOrg> getChildList(List<SysOrg> list, SysOrg t) {
        List<SysOrg> tlist = new ArrayList<SysOrg>();
        Iterator<SysOrg> it = list.iterator();
        while (it.hasNext()) {
            SysOrg n = (SysOrg) it.next();
            if (StringUtils.isNotNull(n.getPid()) && n.getPid().longValue() == t.getId().longValue()) {
                tlist.add(n);
            }
        }
        return tlist;
    }

    /**
     * 判断是否有子节点
     */
    private boolean hasChild(List<SysOrg> list, SysOrg t) {
        return getChildList(list, t).size() > 0;
    }




    /**
     * 获取机构缓存
     */
    @Override
    public List<SysOrg> getDeptCacheAll() {
        List<SysOrg> sysOrgListCache =new ArrayList<>();
        RedisCache redisCache = SpringUtils.getBean(RedisCache.class);
        Collection<String> keys = redisCache.keys(CacheConstants.SYS_DEPT_KEY + "*");
        for (String key : keys) {
            SysOrg cacheObject = redisCache.getCacheObject(key);
            if (StringUtils.isNotNull(cacheObject)){
                sysOrgListCache.add(cacheObject);
            }
        }
        if(!sysOrgListCache.isEmpty()){
            return sysOrgListCache;
        }
        return null;
    }

}
